﻿#include "cached_file.h"
#include <algorithm>
#include <filesystem> // C++17标准文件系统库
#include <filesystem>
#include <klog.h>
#include <knumber.h>
#include <stdexcept>
#include <system_error>

namespace ikit {
bool CachedFile::open(const std::string& filePath, OpenMode mode) {
  close();
  path = filePath;
  file.open(path, static_cast<std::ios::openmode>(mode));
  return isOpen();
}

void CachedFile::close() {
  if (file.is_open()) {
    file.close();
    path.clear();
  }
}

//--- 写入操作 ---
bool CachedFile::writeInt(int32_t value) {
  if (!isOpen()) return false;
  file.write(reinterpret_cast<const char*>(&value), sizeof(value));
  return !file.fail();
}

bool CachedFile::writeFloat(float value) {
  if (!isOpen()) return false;
  file.write(reinterpret_cast<const char*>(&value), sizeof(value));
  return !file.fail();
}

bool CachedFile::writeBytes(const void* data, size_t size) {
  if (!isOpen() || !data) return false;
  file.write(reinterpret_cast<const char*>(data), size);
  return !file.fail();
}

//--- 读取操作 ---
int32_t CachedFile::readInt() {
  int32_t outValue;
  file.read(reinterpret_cast<char*>(&outValue), sizeof(outValue));
  return outValue;
}

float CachedFile::readFloat() {
  float outValue;
  file.read(reinterpret_cast<char*>(&outValue), sizeof(outValue));
  return outValue;
}

bool CachedFile::readBytes(void* outData, size_t size) {
  if (!isOpen() || !outData) return false;
  file.read(reinterpret_cast<char*>(outData), size);
  return !file.fail();
}

// 写入C风格字符串（自动包含null终止符）
bool CachedFile::writeString(const char* str) {
  if (!isOpen()) return false;

  // 处理nullptr情况：写入长度0
  size_t len = str ? strlen(str) : 0;
  if (!writeInt(static_cast<int32_t>(len))) return false;

  // 非nullptr时写入实际数据（包含null终止符）
  return str ? writeBytes(reinterpret_cast<const uint8_t*>(str), len + 1)
             : true;
}

// 读取到预分配缓冲区（确保maxLength足够）
const char* CachedFile::readString(char* outStr) {
  // 读取长度
  int str_len = readInt();

  // 处理长度0情况
  if (str_len == 0) {
    outStr[0] = '\0'; // 设置为空字符串
    return outStr;
  }

  // 读取数据（包含null终止符）
  readBytes(reinterpret_cast<uint8_t*>(outStr), str_len + 1);

  return outStr;
}

// 读取到std::string（自动处理内存）
std::string CachedFile::readString() {
  thread_local std::string buffer; // 线程局部缓存
  buffer.clear();

  // 1. 检查文件是否打开
  if (!isOpen()) {
    return buffer; // 返回空字符串
  }

  // 2. 读取字符串长度
  int32_t len = readInt();
  if (len < 0) {
    ikit::log("readString failed: invalid length");
    return buffer;
  }

  // 3. 处理空字符串情况
  if (len == 0) {
    return buffer;
  }

  // 4. 读取内容
  buffer.resize(len);
  if (!readBytes(reinterpret_cast<uint8_t*>(&buffer[0]), len)) {
    ikit::log("readString failed: read content error");
    buffer.clear(); // 读取失败时清空
  }

  return buffer;
}

//--- 辅助功能 ---
size_t CachedFile::getFileSize() {
  if (!isOpen()) return 0;

  auto prevPos = file.tellg();
  file.seekg(0, std::ios::end);
  size_t size = file.tellg();
  file.seekg(prevPos);
  return size;
}

std::string CachedFile::GetCachedFileName(
    const std::string& filename, const std::string& cached_folder) {
  namespace fs = std::filesystem;

  // 规范化路径
  fs::path file_path(filename);
  fs::path dir_part = file_path.parent_path();
  fs::path name_part = file_path.stem(); // 不带扩展名

  // 计算哈希值
  uint64_t dir_hash = ikit::hash64(dir_part.string().c_str());
  uint64_t name_hash = ikit::hash64(name_part.string().c_str());

  // 组合新文件名
  char new_name[256];
  snprintf(new_name, sizeof(new_name), "%016llx_%016llx.bin",
      (unsigned long long)dir_hash, (unsigned long long)name_hash);

  // 组合完整路径
  fs::path cached_path = fs::path(cached_folder) / new_name;
  return cached_path.string();
}

bool CachedFile::IsCachedValid(
    const std::string& filename, const std::string& cached_filename) {
  namespace fs = std::filesystem;

  try {
    // 1. 检查缓存文件是否存在
    if (!fs::exists(cached_filename)) {
      return false;
    }

    // 2. 检查原始文件是否存在
    if (!fs::exists(filename)) {
      return true; // 原始文件已删除，但保留缓存
    }

    // 3. 比较修改时间
    auto src_time = fs::last_write_time(filename);
    auto cached_time = fs::last_write_time(cached_filename);

    // 如果原始文件比缓存新，则缓存失效
    return src_time <= cached_time;

  } catch (const fs::filesystem_error& e) {
    // 文件操作出错时认为缓存无效
    ikit::log("CachedFile::IsCachedValid error: %s", e.what());
    return false;
  }
}

} // namespace ikit
